package com.tqz.zookeeper.lock;

import com.tqz.zookeeper.common.ZookeeperUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.util.concurrent.CountDownLatch;

/**
 * 使用临时节点实现分布式锁.
 *
 * @author <a href="https://github.com/tian-qingzhao">tianqingzhao</a>
 * @since 2025/9/5 21:00
 */
@Slf4j
public class DistributedLockByEphemeral extends AbstractLock {

    private static final int sessionTimeout = 50000;

    private static final String LOCK_PATH = "/lock-ephemeral";

    private final ZooKeeper zooKeeper;

    private final CountDownLatch countDownLatch = new CountDownLatch(1);

    public DistributedLockByEphemeral() {
        try {
            CountDownLatch connectLatch = new CountDownLatch(1);
            zooKeeper = new ZooKeeper(ZookeeperUtil.ZK_URL, sessionTimeout, event -> {
                // 连接建立时, 打开latch, 唤醒wait在该latch上的线程
                if (event.getState() == Watcher.Event.KeeperState.SyncConnected) {
                    connectLatch.countDown();
                }

                // 发生了waitPath的删除事件
                if (event.getType() == Watcher.Event.EventType.NodeDeleted && event.getPath().equals(LOCK_PATH)) {
                    countDownLatch.countDown();
                }
            });

            // 等待连接建立
            connectLatch.await();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public boolean tryLock() {
        try {
            // 创建临时节点/lock
            zooKeeper.create(LOCK_PATH, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
        } catch (Exception e) {
            // 节点已经存在，创建失败
            return false;
        }

        return true;
    }

    @Override
    public void waitLock() {
        try {
            //判断是否存在，监听节点
            Stat stat = zooKeeper.exists(LOCK_PATH, true);
            if (null != stat) {
                countDownLatch.await();
            }
        } catch (Exception e) {
            log.error("等待锁异常：", e);
        }
    }

    @Override
    public void unlock() {
        try {
            // 删除临时节点
            zooKeeper.delete(LOCK_PATH, -1);
            System.out.println("-------释放锁------");
        } catch (Exception e) {
            log.error("释放锁异常：", e);
        }
    }

}
